package com.danciyixue.boot.client.auth.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.danciyixue.boot.common.constant.SecurityConstants;
import com.danciyixue.boot.client.auth.service.ClientAuthService;
import com.danciyixue.boot.common.exception.BusinessException;
import com.danciyixue.boot.common.result.ResultCode;
import com.danciyixue.boot.core.security.model.AuthenticationToken;
import com.danciyixue.boot.core.security.model.ClientUserDetails;
import com.danciyixue.boot.core.security.token.TokenManager;
import com.danciyixue.boot.core.security.util.SecurityUtils;
import com.danciyixue.boot.dcyx.model.entity.DcyxUsers;
import com.danciyixue.boot.dcyx.model.enums.EffectiveDurationOption;
import com.danciyixue.boot.dcyx.service.DcyxUsersService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

/**
 * 客户端认证服务实现类
 */
@Service
@DS("dcyx")
@Slf4j
public class ClientAuthServiceImpl implements ClientAuthService {

    private final AuthenticationManager clientAuthenticationManager;
    private final TokenManager tokenManager;
    private final DcyxUsersService dcyxUsersService;

    // 显式定义构造器并添加注解
    @Autowired
    public ClientAuthServiceImpl(
            @Qualifier("clientAuthenticationManager") AuthenticationManager clientAuthenticationManager,
            TokenManager tokenManager,
            DcyxUsersService dcyxUsersService) {
        this.clientAuthenticationManager = clientAuthenticationManager;
        this.tokenManager = tokenManager;
        this.dcyxUsersService = dcyxUsersService;
    }

    @Override
    public AuthenticationToken login(String username, String password) {
        // 1. 创建用于密码认证的令牌（未认证）
        String normalizedUsername = username == null ? null : username.trim();
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(normalizedUsername, password);

        // 2. 执行认证（认证中）
        Authentication authentication = clientAuthenticationManager.authenticate(authenticationToken);

        // 3. 认证成功后生成 JWT 令牌，并存入 Security 上下文，供登录日志 AOP 使用（已认证）
        AuthenticationToken authenticationTokenResponse =
                tokenManager.generateToken(authentication);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        return authenticationTokenResponse;
    }

    @Override
    public void ensureActivationForCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            log.warn("登录上下文不存在，无法执行激活校验");
            return;
        }

        Object principal = authentication.getPrincipal();
        if (!(principal instanceof ClientUserDetails clientUserDetails)) {
            if (principal == null) {
                log.warn("当前登录主体缺失，无法执行激活校验");
            } else {
                log.warn("当前登录主体类型不支持激活校验: {}", principal.getClass().getName());
            }
            return;
        }

        Long userId = clientUserDetails.getUserId();
        if (userId == null) {
            log.warn("当前登录主体缺少用户ID，无法执行激活校验");
            return;
        }

        DcyxUsers user = dcyxUsersService.getById(userId);
        if (user == null) {
            log.warn("未找到用户数据，userId={}", userId);
            return;
        }

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expireTime = user.getExpireTime();

        if (expireTime != null && !now.isBefore(expireTime)) {
            throw new BusinessException(ResultCode.USER_LOGIN_EXCEPTION, "账号有效时长已用完，请联系管理员续期");
        }

        LambdaUpdateWrapper<DcyxUsers> updateWrapper = Wrappers.<DcyxUsers>lambdaUpdate()
                .eq(DcyxUsers::getId, userId)
                .set(DcyxUsers::getLoginTime, now);

        if (expireTime == null) {
            EffectiveDurationOption durationOption = user.getEffectiveDuration();
            if (durationOption != null) {
                LocalDateTime calculatedExpireTime = now.plusMonths(durationOption.getMonths());
                updateWrapper.set(DcyxUsers::getExpireTime, calculatedExpireTime);
            } else {
                log.warn("账号缺少有效时长配置，无法计算过期时间，userId={}", userId);
            }
        }

        boolean updated = dcyxUsersService.update(updateWrapper);
        if (!updated) {
            log.error("更新用户登录信息失败，userId={}", userId);
        }
    }

    @Override
    public void logout() {
        String token = SecurityUtils.getTokenFromRequest();
        if (StrUtil.isNotBlank(token) && token.startsWith(SecurityConstants.BEARER_TOKEN_PREFIX)) {
            token = token.substring(SecurityConstants.BEARER_TOKEN_PREFIX.length());
            // 将JWT令牌加入黑名单
            tokenManager.invalidateToken(token);
            // 清除Security上下文
            SecurityContextHolder.clearContext();
        }
    }
} 
